package com.youlu.campus.web.config.aspect;

import com.youlu.campus.service.base.LockService;
import com.youlu.campus.web.common.utils.IpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 定时任务拦截器
 * @author zgz_j
 *
 */
@Component
@Aspect
public class TaskAspect {

	private static final Logger logger = LoggerFactory.getLogger(TaskAspect.class);

	@Autowired
	private LockService lockService;
	
	/**
	 * 切入点
	 */
	@Pointcut("@annotation(com.youlu.campus.web.config.aspect.TaskType) ")
	public void entryPoint() {
	}

	@Around("entryPoint()")
	public Object around(ProceedingJoinPoint joinPoint) {
		long start  = System.currentTimeMillis();
		String cacheKey = "";
		String executeIP = "other";
		try {
			String methodName = joinPoint.getSignature().getName();
			Class<?>[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
			Class<?> targetClass = joinPoint.getTarget().getClass();
			Method realMethod = targetClass.getDeclaredMethod(methodName, parameterTypes);
			TaskType taskType = realMethod.getAnnotation(TaskType.class);
			if(taskType != null) {
				cacheKey = taskType.cacheKey().replace("{METHOD_NAME}", targetClass.getName() + "." + methodName);
				if (lockService.tryLock(cacheKey, taskType.waitTime(), taskType.expireTime(), TimeUnit.SECONDS)) {
					executeIP = IpUtils.getIp();
					logger.info(cacheKey + " execute start on this");
					return joinPoint.proceed();
				}
			}
		} catch (Throwable e) {
			logger.error("after " + joinPoint + " with exception", e);
		} finally {
			long end  = System.currentTimeMillis();
			logger.info(cacheKey + " execute on {} time {}", executeIP, (end -start) / 1000);
		}
		return null;
	}
}